﻿
#include "strid.h"
#include "AppUI.h"

//////////////////////////////////////////////////////////////////////////
//以下为操作控件和资源的便利性封装
ImageRType GetIconType(int ResId)
{
	//资源类型的设计很有问题
	//好在大多数资源都是IT_Bitmap，判断一下就能处理
	if (ResId>=RID_太初_馥郁的欢愉 && ResId<=RID_太初_辨明异徒的食指)
		return IT_Animation;
	if (ResId==RID_Q奶妈 || ResId==RID_Q剑帝)
		return IT_Animation;
	return IT_Bitmap;
}

ImageR_t* EasyLoadImageR(int ResId,ImageRType Type/*=IT_Bitmap*/)
{
	if (Type==IT_Bitmap)
		return ResMgr->LoadImageR(GetResId(ResId));
	else if (Type==IT_Scale9)
		return ResMgr->LoadScale9R(GetResId(ResId));
	else if (Type==IT_Animation)
		return ResMgr->LoadAnimationR(GetResId(ResId));
	return NULL;
}

//先设置位置信息，再设置本体信息
int ControlNextX=0;
int ControlNextY=0;
int ControlPageId=0;
UIControl* ControlParent;

void SetCreateControlParam(int X,int Y,UIControl* Parent,int PageId)
{
	ControlNextX=X;
	ControlNextY=Y;
	ControlParent=Parent;
	ControlPageId=PageId;
}

CButton* EasyCreateButton(int CtrlId,int Width,int Height,WCHAR* Text)
{
	CButton* CtrlButton=new CButton(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height,Text,FALSE);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlButton);
	return CtrlButton;
}

CButton* EasyCreateFlatButton(int CtrlId,int Width,int Height,WCHAR* Text)
{
	CButton* CtrlButton=new CButton(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height,Text,TRUE);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlButton);
	return CtrlButton;
}

CImage* EasyCreateImage(int CtrlId,int Width,int Height,int ResId/*=-1*/,ImageRType Type/*=IT_Bitmap*/)
{
	CImage* CtrlImage=new CImage(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height);
	if (ResId!=-1)
	{
		ImageR_t* ImgRes=EasyLoadImageR(ResId,Type);
		CtrlImage->SetImage(ImgRes);
	}
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlImage);
	return CtrlImage;
}

CLabel* EasyCreateLabel(int CtrlId,int Width,int Height,WCHAR* Text)
{
	CLabel* CtrlLabel=new CLabel(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height,Text);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlLabel);
	return CtrlLabel;
}

CLineLabel* EasyCreateLineLabel(int CtrlId,int Width,int Height,WCHAR* Text)
{
	CLineLabel* CtrlLabel=new CLineLabel(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height,Text);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlLabel);
	return CtrlLabel;
}

CCheckBox* EasyCreateCheckBox(int CtrlId,WCHAR* Text)
{
	CCheckBox* CtrlCheckBox=new CCheckBox(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Text);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlCheckBox);
	return CtrlCheckBox;
}

CVScrollView* EasyCreateScrollView(int CtrlId,int Width,int Height,int VirtualHeight)
{
	CVScrollView* CtrlScrollView=new CVScrollView(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height);
	CtrlScrollView->SetVirtualHeight(VirtualHeight);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlScrollView);
	return CtrlScrollView;
}

CEdit* EasyCreateEdit(int CtrlId,int Width)
{
	CEdit* CtrlEdit=new CEdit(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlEdit);
	return CtrlEdit;
}

CSpListBox* EasyCreateSpListBox(int CtrlId,int Width,int Height)
{
	CSpListBox* CtrlSpListBox=new CSpListBox(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlSpListBox);
	return CtrlSpListBox;
}

CDropList* EasyCreateDropList(int CtrlId,int Width,BOOL IconStyle)
{
	CDropList* CtrlDropList=new CDropList(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,IconStyle);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlDropList);
	return CtrlDropList;
}

CHSlider* EasyCreateSlider(int CtrlId,int Width)
{
	CHSlider* CtrlSlider=new CHSlider(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlSlider);
	return CtrlSlider;
}

CHTabView* EasyCreateTabView(int CtrlId,int Width,int Height)
{
	CHTabView* CtrlTabView=new CHTabView(GetCtrlId(CtrlId),ControlNextX,ControlNextY,Width,Height);
	UiMgr->InsertControl(ControlPageId,ControlParent,CtrlTabView);
	return CtrlTabView;
}


float EditChangeAdjust(CEdit* CtrlEdit,WCHAR* Text,int Len,int RoundNum,BOOL Positive)
{
	WCHAR Buf[20];
	for (int i=0;i<Len;i++)
	{
		//ParseFloatText()会跳过无法解析的字符
		if (Text[i]=='%')
			Text[i]='x';
	}
	float Value=ParseFloatText(Text,Len);
	//为避免受float精度影响，将范围限制在100W以内，这个范围肯定够用
	//但是当数字过大时，末尾的小数精确度会下降，另外UI无法容纳过大的结果
	//如有必要，会加入最大值限制参数，对每个选项的范围控制
	if (Value>999999.9f)
		Value=999999.9f;
	else if (Value<-999999.9f)
		Value=-999999.9f;
	if (Positive && Value<0.0f)
		Value*=-1.0f;
	if (RoundNum<0)
	{
		//整数型的向下取整
		Value=floor(Value);
		swprintf(Buf,L"%d",(int)Value);
		CtrlEdit->SetText(Buf);
	}
	else
	{
		if (RoundNum>7)
			RoundNum=7;
		//百分比型的保留至多7位小数（数字过大时，小数的精确度下降）
		Value=fround(Value,RoundNum);
		//生成0-9的格式化字符串
		WCHAR FmtStr[5]={'%','.','0','f',0};
		FmtStr[2]+=RoundNum;
		swprintf(Buf,FmtStr,Value);
		CtrlEdit->SetText(Buf);
	}
	return Value;
}


//////////////////////////////////////////////////////////////////////////
//以下为装备描述相关代码
std::vector<装备词条描述_t*> 装备词条描述文本[装备描述总数];
std::map<WCHAR*,WCHAR*,wstrless_t> 普通装备描述查找容器;

BOOL 加载装备词条描述(WCHAR* FileName,装备词条描述索引 描述类型)
{
	HANDLE hFile=CreateFile(FileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	if (hFile==INVALID_HANDLE_VALUE)
		return FALSE;
	DWORD FileSize=GetFileSize(hFile,NULL);
	if (FileSize<100)
	{
		CloseHandle(hFile);
		return FALSE;
	}
	WCHAR* DescText=new WCHAR[FileSize/2];
	ReadFile(hFile,DescText,FileSize,&FileSize,NULL);
	CloseHandle(hFile);

	auto 分析自定义专属=[=](WCHAR* Name)->int
	{
		if (描述类型==装备词条描述武器贴膜)
			return 巴卡尔普通系列;
		if (描述类型==装备词条描述武器贴膜龙焰)
			return 巴卡尔龙焰系列;
		if (描述类型==装备词条描述传说贴膜)
			return 传说融合系列;
		if (描述类型==装备词条描述普通 || 描述类型==装备词条描述套装)
			return 非自定义系列;
		int Len=wcslen(Name);
		if (Len<2)
			return 非自定义系列;
		if (memcmp(Name,L"通用",2*sizeof(WCHAR))==0)
			return 通用系列;
		if (memcmp(Name,L"恩特",2*sizeof(WCHAR))==0)
			return 恩特精灵系列;
		if (memcmp(Name,L"魔女",2*sizeof(WCHAR))==0)
			return 森林之魔女系列;
		if (memcmp(Name,L"蓝灵",2*sizeof(WCHAR))==0)
			return 蓝灵绿玉石系列;
		if (memcmp(Name,L"深潜",2*sizeof(WCHAR))==0)
			return 深潜迷航系列;
		if (memcmp(Name,L"海湾",2*sizeof(WCHAR))==0)
			return 海湾侠踪系列;
		//实际没有领域之主专属，领域之主可用所有词条，无视词条内容和专属信息
		//武器和身上的一样也不冲突，视为单独的词条，要注意别误填
		if (memcmp(Name,L"领域",2*sizeof(WCHAR))==0)
			return 领域之主系列;
		return -1;
	};

	enum _State
	{
		SReady,
		SName,
		SDesc,
	} State=SReady;

	//跳过BOM
	int Cur=1;
	int Len=FileSize/2;
	int Pos=Cur;
	装备词条描述_t* 装备描述项=NULL;
	while (Cur<Len)
	{
		if (State==SReady)
		{
			装备描述项=new 装备词条描述_t;
			装备描述项->Name=NULL;
			装备描述项->Num=0;
			memset(装备描述项->Desc,0,10*sizeof(int));
			if (DescText[Cur]=='\r' && DescText[Cur+1]=='\n')
				Cur+=2;
			if (DescText[Cur]=='@')
				Cur++;
			Pos=Cur;
			State=SName;
			continue;
		}
		WCHAR ch=DescText[Cur];
		if (State==SName)
		{
			if (ch=='@')
			{
				//@@作为结束
				delete 装备描述项;
				break;
			}
			else if (ch=='\r')
			{
				DescText[Cur]=0;
				装备描述项->Name=wstrdup(DescText+Pos);
				Pos=Cur+2;
				Cur++;	//跳过\n
				State=SDesc;
			}
		}
		else if (State==SDesc)
		{
			if (ch=='\r')
			{
				//普通描述只有名字和一大块描述
				if (描述类型==装备词条描述普通 || 描述类型==装备词条描述套装)
				{
					if (DescText[Cur+1]=='\n' && DescText[Cur+2]=='@')
					{
						//特别要求两件装备的描述间空一行，描述以上个\r\n结尾（含上个\r\n）
						DescText[Cur]=0;
						装备描述项->Desc[0]=wstrdup(DescText+Pos);
						DescText[Cur]='\r';
						装备描述项->专属系列=非自定义系列;
						装备词条描述文本[描述类型].push_back(装备描述项);
						State=SReady;	//SReady里负责跳过\r\n@序列
						continue;
					}
				}
				//传说贴膜和武器贴膜的描述第一行是名字，后面描述以\r\n拆分
				else if (描述类型>装备词条描述武器)
				{
					if (DescText[Cur+1]=='\n' && DescText[Cur+2]=='@')
					{
						//特别要求两件装备的描述间空一行
						//遇到此序列一定无描述，直接到下个装备
						装备描述项->专属系列=(DNF自定义系列)分析自定义专属(NULL);	//以描述类型区分
						装备词条描述文本[描述类型].push_back(装备描述项);
						State=SReady;	//SReady里负责跳过\r\n@序列
						continue;
					}
					else
					{
						//不含每行的\r\n
						DescText[Cur]=0;
						装备描述项->Desc[装备描述项->Num]=wstrdup(DescText+Pos);
						装备描述项->Num++;
						Pos=Cur+2;
						Cur++;
					}
				}
				//自定义的描述第一行是名字，第二行是专属信息，后面描述以\r\n拆分
				else
				{
					if (DescText[Cur+1]=='\n' && DescText[Cur+2]=='@')
					{
						//特别要求两件装备的描述间空一行
						//遇到此序列一定无描述，直接到下个装备
						装备词条描述文本[描述类型].push_back(装备描述项);
						State=SReady;	//SReady里负责跳过\r\n@序列
						continue;
					}
					else
					{
						//不含每行的\r\n
						DescText[Cur]=0;
						装备描述项->Desc[装备描述项->Num]=wstrdup(DescText+Pos);
						if (装备描述项->Num==0)
							装备描述项->专属系列=(DNF自定义系列)分析自定义专属(装备描述项->Desc[装备描述项->Num]);
						装备描述项->Num++;
						Pos=Cur+2;
						Cur++;
					}
				}
			}
		}
		Cur++;
	}
	delete[] DescText;
	return TRUE;
}

void 加载所有装备描述()
{
	加载装备词条描述(L"Data\\词条描述_上衣.txt",装备词条描述上衣);
	加载装备词条描述(L"Data\\词条描述_下装.txt",装备词条描述下装);
	加载装备词条描述(L"Data\\词条描述_护肩.txt",装备词条描述护肩);
	加载装备词条描述(L"Data\\词条描述_腰带.txt",装备词条描述腰带);
	加载装备词条描述(L"Data\\词条描述_鞋子.txt",装备词条描述鞋子);
	加载装备词条描述(L"Data\\词条描述_手镯.txt",装备词条描述手镯);
	加载装备词条描述(L"Data\\词条描述_项链.txt",装备词条描述项链);
	加载装备词条描述(L"Data\\词条描述_戒指.txt",装备词条描述戒指);
	加载装备词条描述(L"Data\\词条描述_左槽.txt",装备词条描述左槽);
	加载装备词条描述(L"Data\\词条描述_右槽.txt",装备词条描述右槽);
	加载装备词条描述(L"Data\\词条描述_耳环.txt",装备词条描述耳环);
	加载装备词条描述(L"Data\\词条描述_武器.txt",装备词条描述武器);
	加载装备词条描述(L"Data\\词条描述_武器贴膜.txt",装备词条描述武器贴膜);
	加载装备词条描述(L"Data\\词条描述_武器贴膜龙焰.txt",装备词条描述武器贴膜龙焰);
	加载装备词条描述(L"Data\\词条描述_传说贴膜.txt",装备词条描述传说贴膜);
	//可能会分成多个文件，但都放在同一个槽内
	加载装备词条描述(L"Data\\普通装备描述.txt",装备词条描述普通);
	加载装备词条描述(L"Data\\套装装备描述.txt",装备词条描述套装);
	
	std::vector<装备词条描述_t*>::iterator it;
	for (it=装备词条描述文本[装备词条描述普通].begin();it!=装备词条描述文本[装备词条描述普通].end();it++)
	{
		装备词条描述_t* 描述项=*it;
		WCHAR* Text=描述项->Name;
		int Len=wcslen(Text);
		for (int i=0;i<Len;i++)
		{
			//第一个空格前面是序号，后面部分和[DNF装备名称]一致，用来查找
			if (Text[i]==' ')
			{
				普通装备描述查找容器.insert(std::make_pair(Text+i+1,描述项->Desc[0]));
				break;
			}
		}
	}
}

void 清理所有装备描述()
{
	//全是指针引用，直接清理
	普通装备描述查找容器.clear();

	std::vector<装备词条描述_t*>::iterator it;
	for (int i=0;i<装备描述总数;i++)
	{
		for (it=装备词条描述文本[i].begin();it!=装备词条描述文本[i].end();it++)
		{
			装备词条描述_t* 描述记录=*it;
			delete[] 描述记录->Name;
			for (int j=0;j<描述记录->Num;j++)
				delete[] 描述记录->Desc[j];
			delete 描述记录;
		}
		装备词条描述文本[i].clear();
	}
}


//////////////////////////////////////////////////////////////////////////
//以下为伤害结果相关代码，负责计算模块到UI的对接，由计算模块修改
void 伤害计算结果_t::Init()
{
	Valid=FALSE;
}

void 伤害计算结果_t::Uninit()
{

}

void 伤害计算结果_t::SetBase()
{
	总伤害对照=总伤害;

	技能结果对照数=技能结果数;
	for (int i=0;i<技能结果数;i++)
		技能结果对照[i]=技能结果[i];
	for (int i=技能结果数;i<20;i++)
	{
		技能结果对照[i].技能图标Id=-1;
		技能结果对照[i].技能平均伤害=0;
		技能结果对照[i].技能总伤害=0;
	}

	技能冷却结果对照数=技能冷却结果数;
	for (int i=0;i<技能冷却结果数;i++)
		技能冷却结果对照[i]=技能冷却结果[i];
	for (int i=技能冷却结果数;i<20;i++)
	{
		技能冷却结果对照[i].技能图标Id=-1;
		技能冷却结果对照[i].技能当前时间=0;
	}
	
	Valid=TRUE;
}

void 伤害计算结果_t::Sort()
{
	//新结果的技能数量可能变更
	//排序之后，还要让旧结果和新结果的位置一一对应
	//旧结果里不存在的技能，其相关字段已设置为0，不会造成负面影响
	InsertSort(技能结果,技能结果数);
	for (int i=0;i<技能结果数;i++)
	{
		for (int j=0;j<技能结果对照数;j++)
		{
			//以图标ID查找对应技能，交换至位置一致（类似冒泡排序）
			if (技能结果对照[j].技能图标Id==技能结果[i].技能图标Id)
			{
				技能结果_t Temp=技能结果对照[j];
				技能结果对照[j]=技能结果对照[i];
				技能结果对照[i]=Temp;
			}
		}
	}
	
	InsertSort(技能冷却结果,技能冷却结果数);
	for (int i=0;i<技能冷却结果数;i++)
	{
		for (int j=0;j<技能冷却结果对照数;j++)
		{
			//以图标ID查找对应技能，交换至位置一致（类似冒泡排序）
			if (技能冷却结果对照[j].技能图标Id==技能冷却结果[i].技能图标Id)
			{
				技能冷却结果_t Temp=技能冷却结果对照[j];
				技能冷却结果对照[j]=技能冷却结果对照[i];
				技能冷却结果对照[i]=Temp;
			}
		}
	}
}

伤害计算结果_t 伤害计算结果;


